package tosp.search;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;

import org.apache.log4j.Logger;

import tosp.HistoryMachine;
import tosp.JobSequence;
import tosp.job.Job;

public class MostCostNeighborSearch extends LocalSearchAdapter {

	private Logger log = Logger.getLogger(MostCostNeighborSearch.class);
	
	int depth=0;
	
	/**
	 * Sear
	 * @param m the Machine
	 * @param depth 0.. standard depth, 1..5 extended depth
	 */
	public MostCostNeighborSearch(HistoryMachine m, int depth) {
		super(m);
		this.depth=depth;
	}

	public MostCostNeighborSearch(HistoryMachine m) {
		super(m);
		this.depth=0;
	}

	
	@Override
	public JobSequence[] getNeighbors(JobSequence js) {
		final int searchdepth=Math.max(5,Math.min(js.getSize(),js.getSize()*depth/5));
		
		final HistoryMachine m=new HistoryMachine(js);
		Vector<JobSequence> ret=new Vector<JobSequence>(500);
		Vector<Job> jorig=new Vector<Job>(Arrays.asList(m.jobSeq.jobs));
		
		log.debug("Starting with: "+js.getSeqAsString());
		log.debug(m.getSeqCostsAsString());
		
		/*
		// eine liste der kosten anhand der jobid
		final int[] costByJobIndex=new int[m.switchSeq.length];
		for (int i=0;i<m.switchSeq.length;i++) {
			costByJobIndex[m.jobSeq.getJob(i).getID()]=m.switchSeq[i];
		}
		*/
		
		// sortieren nach anzahl der switches
		ConcurrentSkipListSet<Integer> sm=new ConcurrentSkipListSet<Integer>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				//return costByJobIndex[o1]<costByJobIndex[o1]?-1:1;
				return m.switchSeq[o1]>m.switchSeq[o2]?-1:1;
			}});
		//for (Job j:jorig) sm.add(j.getID());
		for (int i=0;i<m.switchSeq.length;i++) sm.add(i);
		
		//debug
		/* for (int k:sm) {
			log.debug("job at pos "+k+" has c="+m.switchSeq[k]+" is job-id="+m.jobSeq.jobs[k].getID());
		}*/
		
		for (int si=0;si<searchdepth && sm.size()>0;si++) {
			Vector<Job> j=(Vector<Job>) jorig.clone();
			int meIndex=sm.pollFirst();	// remove most expensive test

			// log.debug("removed expensive entry index "+meIndex+" (jobid "+m.jobSeq.jobs[meIndex].getID()+") with switches="+m.switchSeq[meIndex]);
			
			Job ej=j.get(meIndex); // ej=expensive job
			j.remove(meIndex);
			
			for (int i=0;i<js.getSize()-1;i++) {
				if (i==meIndex) continue;
				Vector<Job> j1=(Vector<Job>)j.clone();
				j1.add(i,ej);
				JobSequence newjs = new JobSequence(j1,true);
				// log.trace("Generated new Neighbor: "+newjs.getSeqAsString()); // is O(n) (!!!)
				ret.add(newjs);
			}
			
			
		}
		ret.trimToSize();
		log.debug("Generated a Total of "+ ret.size() +" Neighbors");
		return ret.toArray(new JobSequence[ret.size()]);
	}

}
